package org.visionlibrary.image.filters.frequency;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.acquisition.ImageFactory;
import org.visionlibrary.image.model.AbstractFilter;
import org.visionlibrary.image.model.FilterTools;
import org.visionlibrary.image.model.FilterTools.Complex;


public class FFTSmoothLowPass extends AbstractFilter {
	private int cutoff;

	private int omega;

	public FFTSmoothLowPass(int cutoff, int omega) {
		this.cutoff = cutoff;
		this.omega = omega;
	}

	public FFTSmoothLowPass(int cutoff) {
		this(cutoff, 0);
	}

	public FFTSmoothLowPass() {
		this(25, 3);
	}

	public TiledImage applyFilter(TiledImage src, TiledImage dest) {
		if (null == src)
			throw new NullPointerException("Source image is null.");

		if (null == dest)
			dest = (new ImageFactory()).createCompatibleImage(src);

		int plusOmega2 = (cutoff + omega) * (cutoff + omega);
		int minusOmega2 = (cutoff - omega) * (cutoff - omega);

		for (int ch = 0; ch < src.getNumBands(); ch++) {
			Complex[][] complexImage = FilterTools.getComplex(src, ch);
			Complex[][] fft = FilterTools.simpleFFT(complexImage);
			FilterTools.Complex.revertQuarters(fft);

			int N = fft.length;
			int M = fft[0].length;

			int N2 = N / 2;
			int M2 = M / 2;

			if (omega != 0)
				for (int i = 0; i < N; i++)
					for (int j = 0; j < M; j++) {
						int distance2 = (i - N2) * (i - N2) + (j - M2)
								* (j - M2);
						if (distance2 > plusOmega2)
							fft[i][j] = new Complex();
						else if (distance2 > minusOmega2) {
							float arg = (float) Math.PI
									* ((float) (Math.sqrt(distance2) - cutoff))
									/ (float) (2 * omega);
							float sinValue = 1.0f - (float) Math.sin(arg);
							sinValue /= 2.0;
							fft[i][j] = fft[i][j].times(sinValue); //
						}

					}
			else
				for (int i = 0; i < N; i++)
					for (int j = 0; j < M; j++) {
						int distance2 = (i - N2) * (i - N2) + (j - M2)
								* (j - M2);
						if (distance2 > plusOmega2)
							fft[i][j] = new Complex();
					}

			FilterTools.Complex.revertQuarters(fft);
			Complex[][] ifft = FilterTools.inverseFFT(fft);
			for (int x = 0; x < src.getWidth(); x++)
				for (int y = 0; y < src.getHeight(); y++)
					dest.setSample(x, y, ch, normalization
							.normalize((int) ifft[y][x].re()));
		}
		return dest;
	}
}
